<?php
/**
* Класс обеспечивает соединение с базой данных
* Автоматически формирует массивы
* Обеспечивает обработку исключительных ситуаций при осуществлении запросов
*
*/

class Service_Database{
private $hConn;   //Дескриптор соединения с базой данных
private $cntQueries;   //Количество запросов
/**
* Конструктор - устанавливаем соединение с БД.
*
*/
private function __construct() {

$hostName  = DB_HOST . ":" . DB_PORT;

$this->hConn = @mysql_connect($hostName, DB_USER, DB_PASSWORD);
mysql_set_charset('utf8', $this->hConn);

if(! is_resource($this->hConn)) {
throw new Exception("Невозможно соединиться с базой данных " .
"Хост: \"$hostName\"; Пользователь: \"". DB_USER. "\"", E_USER_ERROR);
}
$curBD = @mysql_select_db(DB_NAME);//Выбираем базу данных для работы
if(! ($curBD)) {
throw new Exception("Невозможно выбрать базу данных " .
"База данных: \"" . DB_NAME . "\"", E_USER_ERROR);
}
@mysql_query("SET NAMES 'utf8'");
}

/**
* Функция обеспечивает работу шаблона Singleton. Благодаря ей у нас всегда будет только одно подключение к базе
*
* @return resource
*/
static public function instance(){
static $objDb;
static $cntQueries;
if(!isset($objDb)){
$objDb = new Service_Database();
$cntQueries = 0;
}
return $objDb;
}

/**
* Получает информацию о последнем вставленном идентификаторе
*
* @return integer - значение последнего вставленно идентификатора (false, если не было удачного запроса; 0 если в таблице нет autoincrement)
*/
public function getLastInsertId(){
$stmt = "SELECT LAST_INSERT_ID() AS LID";
$hRes = mysql_query($stmt, $this->hConn);
if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $stmt;
throw new Exception($err);
}
$arrLID = mysql_fetch_assoc($hRes);
return $arrLID['LID'];
}
/**
* Вставляет в определенную таблицу массив значений
*
* @param string $table - название таблицы
* @param array $arFieldValues - массив вставляемых значений (ключ соответствует полю в БД)
* @return integer - количество вставленных строк
*/
public function insert($table, $arFieldValues) {
$fields = array_keys($arFieldValues);     //Массив названий элементов таблицы
$values = array_values($arFieldValues);   //Массив значений

$escVals = array();   //Выходной массив значений
foreach($values as $val) {  //Проходим массив значений поэлементно
if(! is_numeric($val)) {  //Если текущее значение - не число
$val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
}
$escVals[] = $val;  //Записываем корректное значение в массив
}
//Генерируем SQL запрос
$sql = " INSERT INTO `". $table . "` ( ";
$sql .= join(", ", $fields);
$sql .= ' ) VALUES( ';
$sql .= join(', ', $escVals);
$sql .= ' )';
$hRes = @mysql_query($sql, $this->hConn) or die ("Невозможно выполнить запрос" . $sql . $this->hConn);
if(! $hRes) {  //Если не получен положительный результат о вставке
$err = mysql_error($this->hConn) . "\n" . $sql;
throw new Exception($err);
}
$this->_incrementCntQueries();
return mysql_affected_rows($this->hConn);
}

private function _incrementCntQueries() {
$this->cntQueries++;
//$cntQueries++;
}

public function getCntQueries() {
return $this->cntQueries;
}

/**
* Вставляет в определенную таблицу массив значений
*
* @param string $table - название таблицы
* @param array $arFieldValues - массив вставляемых значений (ключ соответствует полю в БД)
* @return integer - идентификатор вставленого элемента
*/
public function insertAutoincrement($table, $arFieldValues) {
if( $this->insert($table, $arFieldValues) )
return $this->getLastInsertId();
else
return false;
}
/**
* Выполняет запрос на вставку значений
*
* @param string $sql - строка запроса
* @return integer - идентификатор
*/
public function queryInsertAutoincrement($sql) {
if( $this->query($sql) > 0)
return $this->getLastInsertId();
else
return false;
}

/**
* Удаляет из таблицы все элементы, удовлетворяющие условию
*
* @param string $table - название таблицы
* @param array $arConditions - массив условий (ключ соответствует полю в БД)
* @return integer - количество удаленных строк
*/
function delete($table, $arConditions) {

//Создаем строку WHERE
$arWhere = array();//Массив элементов для WHERE
foreach($arConditions as $field => $val) {  //Проходим массив значений поэлементно
if(! is_numeric($val)) {  //Если текущее значение - не число
$val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
}

$arWhere[] = "$field = $val";//Записываем корректное значение в массив
}
//Формируем запрос на удаление
$sql = "DELETE FROM $table WHERE " . join(' AND ', $arWhere);

$hRes = @mysql_query($sql, $this->hConn) or die ("Невозможно выполнить запрос на удаление" . $sql . $this->hConn);
if(! $hRes) {  //Если не получен положительный результат о вставке
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
$this->_incrementCntQueries();
return mysql_affected_rows($this->hConn);
}

/**
* выполняет любой запрос SQL типа SELECT
*
* @param string $sql - строка запроса
* @return array - двумерный ассоциативный массив
*/
public function select($sql) {
$hRes = @mysql_query($sql, $this->hConn);
if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
$arReturn = array();//Массив для возвращения функцией (результат)
while( ($row = @mysql_fetch_assoc($hRes)) ) {
$arReturn[] = $row;
}
$this->_incrementCntQueries();
return $arReturn;
}

/**
* выполняет любой запрос SQL типа SELECT для получения информации об одном поле и возвращает простой одномерный массив
*
* @param string $sql - строка запроса
* @return array - одномерный индексный массив
*/
public function selectSimpleArray($sql) {
$hRes = @mysql_query($sql, $this->hConn);

if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
if( mysql_num_rows($hRes) == 0 )
return NULL;
$arReturn = array();//Массив для возвращения функцией (результат)
while( ($row = mysql_fetch_array($hRes)) ) {
$arReturn[] = $row[0];
}
$this->_incrementCntQueries();
return $arReturn;
}
/**
* выполняет любой запрос SQL типа SELECT для получения информации об одном поле одной строки
*
* @param string $sql - строка запроса
* @return mixed - значение единственного поля
*/

public function selectSimpleField($sql) {
$hRes = @mysql_query($sql, $this->hConn);

if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
else {
if( mysql_num_rows($hRes) == 0 ) return NULL;
$arTemp =  mysql_fetch_array($hRes);
$this->_incrementCntQueries();
return $arTemp[0];
}
}

/**
* выполняет любой запрос SQL типа SELECT, возвращает только первый элемент
*
* @param string $sql - строка запроса
* @return array - двумерный ассоциативный массив
*/
public function selectOne($sql) {
$hRes = @mysql_query($sql, $this->hConn);
if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
if( mysql_num_rows($hRes) == 0 )
return NULL;
$this->_incrementCntQueries();
return mysql_fetch_assoc($hRes);
}

/**
* Выполняет произвольный SQL запрос
*
* @param string $sql - строка запроса
* @return integer - количество обработанных строк
*/
public function query($sql) {
$hRes = @mysql_query($sql, $this->hConn);
if(! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
$this->_incrementCntQueries();
return @mysql_affected_rows($this->hConn);
}

//Функция обновляет в таблице $table поля $arFieldValues, но только те элементы, которые соотвествуют условию $arConditions
/**
* Обновляет в таблице определенные поля, согласно условию
*
* @param string $table - название таблицы
* @param array $arFieldValues - массив обновляемых значений (ключ соответствует полю в БД)
* @param array $arConditions - массив условий (ключ соответствует полю в БД)
* @return integer - количество обновленных строк
*/
public function update($table, $arFieldValues, $arConditions) {
// Формируем корректный массив значений
$arUpdates = array();//Массив элементов для значений
foreach($arFieldValues as $field => $val) {//Проходим массив значений поэлементно
if(! is_numeric($val)) { //Если текущее значение - не число
$val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
}
$arUpdates[] = "$field = $val";//Записываем корректное значение в массив
}

// Формируем корректный массив WHERE
$arWhere = array();//Массив элементов для WHERE
foreach($arConditions as $field => $val) {//Проходим массив WHERE поэлементно
if(! is_numeric($val)) { //Если текущее значение - не число
$val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
}
$arWhere[] = "$field = $val";//Записываем корректное значение в массив
}
//Формируем SQL-запрос на обновление данных
$sql  = "UPDATE $table SET ";
$sql .= join(', ', $arUpdates);
$sql .= ' WHERE ' . join(' AND ', $arWhere);
$hRes = mysql_query($sql, $this->hConn);//Выполняем запрос
if(! $hRes) {//Проверяем запрос на корректность
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
$this->_incrementCntQueries();
return mysql_affected_rows($this->hConn);
}

/**
* Проеряет, существует ли запись в БД
*
* @param string $sql
* @return bool
*/
public function isRecordExist($sql) {
$hRes = @mysql_query($sql, $this->hConn);

if (! $hRes) {//Проверяем, корректно ливыполнен запрос
$err = mysql_error($this->hConn) . $sql;
throw new Exception($err);
}
if ( mysql_num_rows($hRes) > 0 )
return true;
else
return false;
}

/**
* Деструктор - закрываем соединение с базой данных
*
*/
public function __destruct() {
if(is_resource($this->hConn)) {
@mysql_close($this->hConn);
}
}
}
?>